const CAN_BET = ['HXEB', 'JNDEB', 'PCNN', 'PCBJL', 'JNDSI', 'JNDWU', 'JNDWP', 'JNDSSC']
import { showToast } from 'vant'
import { hasOwnProperty } from '@/utils'
import { getHistoryMessages } from '@/api'
import { useUserStore } from '@/stores/user'
import { useGameStore } from '@/stores/game'
import { useInvestStore } from '@/stores/invest'
import { useRoute } from 'vue-router'
import { useAppStore } from '@/stores/app'
import { GAME_STATUS_CODE } from '@/enum'

export default {
  data() {
    return {
      socket: null,
      apiAddress: import.meta.env.VITE_WS_CHAT,
      // apiAddress: process.env.VUE_APP_WS_CHAT,
      messageList: [],
      timer: null,
      loading: false,
      hiddenTime: 0,
      unreadCount: 0,
      msgIsLatest: false,
      initalBottom: true,
      calculatedIndex: 100,
      isInBottom: true,
      showToBottomBtn: false,
      userStore: useUserStore(),
      gameStore: useGameStore(),
      route: useRoute(),
      appStore: useAppStore(),
      investStore: useInvestStore(),
    }
  },

  watch: {
    currentGame: {
      handler(n) {
        if (!n) return
        this.messageList = []
        this.isInBottom = true
        this.showToBottomBtn = false
        this.initalBottom = true
        this.msgIsLatest = false
        this.handleCurrentGame()
        this.isShowBetTip = CAN_BET.includes(n)
      },
      immediate: true,
    },
  },

  mounted() {
    document.addEventListener('visibilitychange', this.handlePageHide)
  },

  beforeUnmount() {
    this.socket?.close?.()
    document.removeEventListener('visibilitychange', this.handlePageHide)
  },

  methods: {
    handleCurrentGame() {
      this.historyInit()

      if (this.socket?.readyState === 1) {
        this.joinGroup()
      } else {
        this.initWebsocket()
      }
    },

    handlePageHide() {
      if (document.visibilityState === 'hidden') {
        this.hiddenTime = new Date().getTime()
      } else {
        const now = new Date().getTime()
        if (now - this.hiddenTime >= 10000) {
          this.socket?.close?.()
          if (this.msgIsLatest) {
            this.resetHistoryToNew()
          }

          setTimeout(() => {
            this.initWebsocket()
          }, 150)
        }
      }
    },

    handleWsMsg(msgContent) {
      if (this.msgIsLatest) {
        this.messageList.push(msgContent)
      }

      if (!this.isInBottom) {
        this.unreadCount += 1
      } else {
        this.saveTime(msgContent.msgTime)
      }
    },

    initWebsocket() {
      if (this.socket?.readyState === 1) {
        this.socket.close()
      }

      this.connect()

      if (this.socket) {
        this.socket.onerror = () => {
          this.socket.close()
        }

        this.socket.onopen = () => {
          // 要加心跳， 放这

          this.joinGroup()
        }

        this.socket.onclose = () => {
          // 关闭
          console.log('ws close')
          // this.connect();
        }

        this.socket.onmessage = (e) => {
          const response = JSON.parse(e.data)
          // type 消息推送类型 目前分为两种：1.CHAT_SEND_RESPONSE 发送消息的响应 2.CHAT_PUSH_RESPONSE 监听收到的消息
          const msgType = response.type
          // message 消息内容
          const msgContent = JSON.parse(response.message)

          // 发送消息响应(自己发出去的消息 成功/失败， 200即为成功，会生成一个唯一消息记录ID:msgId，
          // 同时请求体可以设置参数requestUUId，响应体也会返回相应requestUUId,可以以此校验是哪条消息发送成功)
          // {"message":"{\"code\":200,\"msgId\":1706143326582026241}","type":"CHAT_SEND_RESPONSE"}
          // if (msgType === 5) {
          //   // do something
          // }

          if (msgType === 7) {
            showToast({
              type: 'fail',
              message: msgContent.content,
              forbidClick: true,
              duration: 3000,
            })
          }

          // 监听消息推送响应(监听来自客户端推送的消息，根据不同消息类型决定展示方式)
          if (msgType === 6) {
            // 1, 正常聊天消息推送
            if (msgContent.messageType === 1) {
              this.handleWsMsg(msgContent)
              // 临时
              if (msgContent.senderId === Number(this.userId) && msgContent.remark) {
                this.userStore.getBalance()
                this.investStore.findOrderPage()
              }
            } else if (msgContent.messageType === 2) {
              // 2, 系统消息推送
              this.handleWsMsg(msgContent)

              if (hasOwnProperty(msgContent, 'lotteryStatus')) {
                if (GAME_STATUS_CODE.kaijiang.code === msgContent.lotteryStatus) {
                  this.investStore.findOrderPage()
                }

                this.gameStore.setDrawingStatus(msgContent.lotteryStatus)

                // GAME_STATUS_CODE
              }
            } else if (msgContent.messageType === 6) {
              // 6, 撤单警告

              this.cancelId = msgContent?.refMessage?.id
              this.showCancelPopup()
            }
            //  else if (msgContent.messageType === 3) {
            //   // 3, 频道人数推送
            //   console.log(3);
            // }
            this.setVirtualListToBottom()
          }
        }
      }
    },

    setVirtualListToBottom() {
      if (!this.isInBottom || this.appStore.isProBet || !this.route.path.includes('/bet')) return

      this.$nextTick(() => {
        setTimeout(() => {
          this.$refs.vsl?.scrollToBottom?.()
        }, 150)
      })
    },

    connect() {
      const url = this.apiAddress + '/ws/chat'

      if (this.socket && this.socket.readyState === 1) {
        this.joinGroup()
      } else {
        this.socket = new WebSocket(url, this.token)
      }
    },

    joinGroup() {
      const message = {
        type: 2,
        message: {
          requestUUId: '',
          gameCode: 1,
          groupCode: this.currentGame,
        },
      }
      this.socket?.send?.(JSON.stringify(message))
    },

    async sendMessage() {
      if (!this.msgIsLatest) {
        await this.resetHistoryToNew()
      }

      if (!this.inputValue.trim()) return

      const message = {
        type: 4,
        message: {
          requestUUId: '',
          content: this.inputValue,
          contentType: 1,
        },
      }
      this.socket.send(JSON.stringify(message))
      this.inputValue = ''
      this.isInBottom = true
    },

    async historyInit() {
      const lastTime = localStorage.getItem(this.currentGame)

      this.initalBottom = true

      let params = {
        receiver: this.currentGame,
      }

      if (lastTime) {
        params = { ...params, startTime: lastTime, backwardLimit: 50, forwardLimit: 100 }
      } else {
        params = { ...params, isForward: true, forwardLimit: 100 }
      }

      const data = await this.fetchHistory(params)

      if (data?.count <= 50) {
        this.msgIsLatest = true
      }

      this.unreadCount = data?.count ?? 0

      if (data?.historyList?.length) {
        this.messageList = data.historyList.concat(this.messageList)
      }

      this.$nextTick(() => {
        setTimeout(() => {
          if (data?.count > 10) {
            this.$refs?.vsl?.scrollToIndex(101)
            setTimeout(() => {
              this.initalBottom = false
            }, 500)
          } else {
            setTimeout(() => {
              this.isInBottom = true
              this.setVirtualListToBottom()
            }, 350)
          }
        }, 250)
      })
    },

    async historyTop() {
      const params = {
        receiver: this.currentGame,
        isForward: true,
        forwardLimit: 100,
        startTime: this.messageList[0].msgTime,
      }

      const data = await this.fetchHistory(params)

      if (data?.historyList?.length) {
        this.messageList = data.historyList.concat(this.messageList)
      }

      this.calculatedIndex += 100

      this.$nextTick(() => {
        setTimeout(() => {
          this.$refs?.vsl?.scrollToIndex(99)
        }, 250)
      })
    },

    async historyBottom() {
      if (this.initalBottom) return
      if (this.msgIsLatest) return
      if (this.loading) return

      const params = {
        receiver: this.currentGame,
        backwardLimit: 100,
        startTime: this.messageList.at(-1).msgTime,
      }

      const data = await this.fetchHistory(params)

      if (data?.historyList?.length) {
        this.messageList = this.messageList.concat(data.historyList)
      }

      this.msgIsLatest = data?.count <= 100

      this.unreadCount = data?.count ?? 0
    },

    async resetHistoryToNew() {
      this.msgIsLatest = true

      try {
        const params = {
          receiver: this.currentGame,
          isForward: true,
          forwardLimit: 100,
          backwardLimit: 0,
        }

        const data = await this.fetchHistory(params)

        this.messageList.splice(0, this.messageList.length)

        this.messageList = data.historyList

        this.unreadCount = 0

        this.isInBottom = true

        this.calculatedIndex = this.messageList.length - 1

        this.calculatedIndex = 100

        this.saveTime(this.messageList.at(-1).msgTime)

        this.setVirtualListToBottom()
      } catch {
        /* empty */
      }
    },

    async fetchHistory(params) {
      this.loading = true

      try {
        const { data } = await getHistoryMessages(params)

        this.loading = false

        return data
      } catch {
        /* empty */
      }
    },

    calcUnreadCount(list) {
      if (!list) return

      const len = list.length - 1

      const thdLastNode = list[len]

      const min = thdLastNode?.getAttribute?.('data-index')

      if (min < this.calculatedIndex) return

      const _list = Array.from(list)

      let i = _list.findLastIndex((item) => {
        const style = item?.getBoundingClientRect?.()
        if (style.y > 150 && style.y < window.innerHeight) {
          return true
        }
        return false
      })

      if (i === -1) return

      const index = list[i].getAttribute('data-index')

      if (index < this.calculatedIndex) return

      const diff = index - this.calculatedIndex

      if (diff < 1) return

      this.unreadCount -= diff

      this.calculatedIndex = index

      const t = this.messageList?.[index]?.msgTime

      if (t) this.saveTime(t)
    },

    handleIsBottom(e) {
      const ele = e.target
      const currentScroll = ele?.scrollTop
      const childHeight = ele?.children?.[1]?.clientHeight ?? 0
      const viewHeight = this.$refs?.vsl?.$el?.clientHeight

      const isBottom = currentScroll + viewHeight + 30 >= childHeight

      this.isInBottom = isBottom

      this.showToBottomBtn = !isBottom

      if (this.isInBottom) {
        this.unreadCount = 0
        this.calculatedIndex = this.messageList.length - 1
      }
    },

    onScroll(e) {
      if (this.timer) clearTimeout(this.timer)

      this.showToBottomBtn = true

      if (!this.isInBottom && this.unreadCount > 0) {
        const vsl = this.$refs.vsl.$el

        const children = vsl.querySelectorAll('.message-item')

        this.calcUnreadCount(children)
      }

      this.timer = setTimeout(() => {
        this.handleIsBottom(e)
      }, 300)
    },

    handleShowPopup() {
      this.$refs.rules.open()
    },

    showCancelPopup() {
      this.showCancelOrder = true
      this.$nextTick(() => {
        this.$refs.invest.openCancelOrderPopup(true)
      })
    },

    clickToBottom() {
      if (this.msgIsLatest) {
        this.isInBottom = true
        this.setVirtualListToBottom()

        setTimeout(() => {
          this.showToBottomBtn = false
          this.unreadCount = 0
        }, 200)
      } else {
        this.resetHistoryToNew()
      }
    },

    onToTop() {
      this.historyTop()
    },

    onBottom() {
      if (this.msgIsLatest) return
      this.historyBottom()
    },

    saveTime(t) {
      localStorage.setItem(this.currentGame, t)
    },
  },
}
